package org.custom.spring.boot.mybatis.service.plugin.algorithm.impl;

import cn.hutool.core.util.ObjectUtil;
import org.custom.spring.boot.constant.MagicValue;
import org.custom.spring.boot.mybatis.entity.MybatisAlgorithmMetadata;
import org.custom.spring.boot.mybatis.entity.MybatisMapping;
import org.custom.spring.boot.mybatis.service.plugin.algorithm.MybatisAlgorithm;
import org.custom.spring.boot.mybatis.utils.MybatisPlugInUtil;

import java.util.List;
import java.util.Objects;

/**
 * Mybatis SQL 语句执行记录插件
 *
 * @author 李坤
 */
public class MybatisExecuteLoggerAlgorithm implements MybatisAlgorithm {
    /**
     * 将占位符替换为给定的参数值
     *
     * @param sql      元SQL
     * @param mappings 参数映射
     *
     * @return 格式化后的SQL
     */
    private static String replacePlaceholdersWithParameters(String sql, List<MybatisMapping> mappings) {
        // 将 问号替-? 换为 占位符-@
        sql = sql.replace(MagicValue.QUESTION_MARK, MagicValue.PLACEHOLDER);

        if (ObjectUtil.isNotEmpty(mappings)) {
            int length = mappings.size() - 1;
            // 以 问号-? 为切分符切割SQL
            String[] split = sql.split(MagicValue.PLACEHOLDER);
            // 设置字符串构造器
            StringBuilder builder = new StringBuilder(mappings.size() << 1);

            for (int index = 0; index <= length; ) {
                String value = getFormatMybatisMapping2Sql(mappings.get(index));
                builder.append(split[index++]).append(value);
            }

            if (!sql.endsWith(MagicValue.PLACEHOLDER)) {
                builder.append(split[split.length - 1]);
            }
            sql = builder.toString();
        }
        return sql + MagicValue.SEMICOLON;
    }

    /*--------------------------------------------------private methods-----------------------------------------------*/

    /**
     * 将参数转换为可以直接拼接到SQL中的字符串
     *
     * @param mapping 参数映射
     *
     * @return 字符串
     */
    private static String getFormatMybatisMapping2Sql(MybatisMapping mapping) {
        Object mappingValue = mapping.getValue();

        if (Objects.isNull(mappingValue)) {
            return String.valueOf(mappingValue);
        } else {
            String result = MagicValue.EMPTY;

            switch (mapping.getJdbcType()) {
                case INTEGER:
                case DECIMAL:
                    result = String.valueOf(mappingValue);
                    break;
                case DATE:
                case VARCHAR:
                case TIMESTAMP:
                    result = MagicValue.APOSTROPHE + mappingValue + MagicValue.APOSTROPHE;
                    break;
                default:
                    break;
            }
            return result;
        }
    }

    @Override
    public String execute(MybatisAlgorithmMetadata algorithmMetadata) {
        // 格式化SQL代码样式，简化空间
        String sql = MybatisPlugInUtil.formatSql(algorithmMetadata.getBoundSql().getSql());
        // 将占位符替换为给定的有意义的参数
        return MybatisExecuteLoggerAlgorithm.replacePlaceholdersWithParameters(sql, algorithmMetadata.getMybatisMappings());
    }
}
